package com.nq.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nq.common.Result;
import com.nq.common.ServerResponse;
import com.nq.common.entity.StStockTickerDetails;
import com.nq.common.entity.StStockTickerKLineList;
import com.nq.common.entity.State;
import com.nq.common.entity.info.StockTickerListInfo;
import com.nq.dao.MyDao;
import com.nq.fund.entity.StFundKline;
import com.nq.pojo.SiteSetting;
import com.nq.pojo.StockListPO;
import com.nq.service.ISiteSettingService;
import com.nq.service.IStockService;
import com.nq.service.StockDzService;
import com.nq.service.TimerService;
import com.nq.stock.entity.KLineDetail;
import com.nq.stock.entity.StStockTicker;
import com.nq.stock.service.IStStockTickerService;
import com.nq.stock.vo.StStockIndexVo;
import com.nq.stock.vo.StStockTickerKLineVO;
import com.nq.utils.InvestingUtil;
import com.nq.utils.TGStockApiUtil;
import com.nq.utils.stock.BuyAndSellUtils;
import com.nq.utils.task.tsanghi.StocksComponent;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping({"/api/stock/"})
public class StockApiController {
    private static final Logger log = LoggerFactory.getLogger(StockApiController.class);

    @Autowired
    IStockService iStockService;

    @Autowired
    TimerService timerService;

    @Resource
    SqlSessionTemplate sessionTemplate;

    @Autowired
    StockDzService stockDzService;
    @Autowired
    private StocksComponent stocksComponent;
    @Autowired
    private IStStockTickerService stStockTickerService;
    @Autowired
    private ISiteSettingService siteSettingService;

    /**
     * 模拟基金分页列表查询
     *
     * @param stFundKline
     * @param req
     * @return
     */
    @RequestMapping({"fundList.do"})
    @ResponseBody
    public ServerResponse fundList(StFundKline stFundKline,
                                   @RequestParam("changePercent") String changePercent,
                                   @RequestParam(name="pageNo", defaultValue="1") Integer pageNum,
                                   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                   HttpServletRequest req) {

        return iStockService.fundList(pageNum, pageSize, changePercent, req);
    }
    /**
     * 模拟基金K线图  查最近100条
     *
     * @param fundCode
     * @param req
     * @return
     */
    @RequestMapping({"fundKLineList.do"})
    @ResponseBody
    public ServerResponse fundKLineList(@RequestParam("fundCode") String fundCode,
                                   @RequestParam(name="pageNo", defaultValue="1") Integer pageNum,
                                   @RequestParam(name="pageSize", defaultValue="100") Integer pageSize,
                                   HttpServletRequest req) {

        return iStockService.fundKLineList(fundCode, pageNum, pageSize);
    }
    /**
     * 模拟基金详情
     *
     * @param fundCode
     * @param req
     * @return
     */
    @RequestMapping({"queryFund.do"})
    @ResponseBody
    public ServerResponse queryFund(@RequestParam("fundCode") String fundCode,
                                   HttpServletRequest req) {

        return iStockService.queryFund(fundCode);
    }

    /**
     * 股票详情分页列表查询
     * @param req
     * @return
     */
    @RequestMapping({"stockList.do"})
    @ResponseBody
    public Result<?> stockList(StockListPO stockInfoPO,
                               @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                               @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                               HttpServletRequest req) {

        QueryWrapper<StStockTicker> queryWrapper = new QueryWrapper<>();

        String country = stockInfoPO.getCountry();
        if(StringUtils.isNotBlank(country)){
            // 查询 SH  SZ 交易所数据
            queryWrapper.and(qw -> qw.eq("market", country));
        }

        String stockInfo = stockInfoPO.getStockInfo();
        // 根据股票信息查询
        if (StringUtils.isNotBlank(stockInfo)) {
            queryWrapper.and(qw -> qw.like("code", stockInfo));
        }

        // 判断更新时间大于十五天的股票被认为已下架
        queryWrapper.ge("update_time", DateUtil.offsetDay(new Date(), -15));

        String changePercent = stockInfoPO.getChangePercent();
        // 按照涨跌幅排序
        if (State.STATE_S1.equals(changePercent)) {
            queryWrapper.orderByAsc("up");
        } else {
            queryWrapper.orderByDesc("up");
        }

        String sort = stockInfoPO.getSort();
        try {
            // 判断交易时间
            SiteSetting siteSetting = siteSettingService.getSiteSetting();
            // 交易时间
            String transAmBegin = siteSetting.getTransAmBegin();
            String transAmEnd = siteSetting.getTransAmEnd();
            String transPmBegin = siteSetting.getTransPmBegin();
            String transPmEnd = siteSetting.getTransPmEnd();

            boolean am = false;
            boolean pm = false;
            am = BuyAndSellUtils.isTransTime(transAmBegin, transAmEnd);
            pm = BuyAndSellUtils.isTransTime(transPmBegin, transPmEnd);
            log.info("am = {}  pm = {}", Boolean.valueOf(am), Boolean.valueOf(pm));
            if ((!am && !pm) || StockListPO.IS_SORT_YES.equals(sort)) {
                log.info("am = {}  pm = {}", Boolean.valueOf(am), Boolean.valueOf(pm) + "不在交易时间内,股票列表直接查询数据库");
                Page<StStockTicker> page = new Page<StStockTicker>(pageNo, pageSize);
                IPage<StStockTicker> pageList = stStockTickerService.page(page, queryWrapper);
                return Result.OK(pageList);
            }
        } catch (Exception e) {
            log.error("获取股票列表失败，country={}", country);
            throw new RuntimeException(e);
        }

        Page<StStockTicker> page = new Page<StStockTicker>(pageNo, pageSize);
        IPage<StStockTicker> pageList = stStockTickerService.page(page, queryWrapper);

        List<StStockTicker> records = pageList.getRecords();

        List<StockTickerListInfo> tickerListInfos = new ArrayList<>();

        Map<String, List<StStockTicker>> collect = records.stream().collect(Collectors.groupingBy(StStockTicker::getMarket));
        for (Map.Entry<String, List<StStockTicker>> entry : collect.entrySet()) {
            String market = entry.getKey();
            List<StStockTicker> list = entry.getValue();
            String codes = list.stream().map(StStockTicker::getCode).collect(Collectors.joining(","));

            // 调用股票接口查询股票信息
            tickerListInfos.addAll(stocksComponent.queryRealTimeData(market, codes));

            // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_PRICES, "stockList");

        }

        for (StStockTicker ticker : records) {
            // 找到对应的 StockTickerListInfo
            Optional<StockTickerListInfo> optionalInfo = tickerListInfos.stream()
                    .filter(info -> info.getCode().equals(ticker.getCode()))
                    .filter(info -> info.getMarket().equals(ticker.getMarket()))
                    .findFirst();

            // 如果找到了对应的实时数据，则更新 StStockTicker 对象
            optionalInfo.ifPresent(info -> {
                ticker.setPrice(info.getPrice());
                ticker.setUp(info.getUp());
                ticker.setChange(info.getChange());
            });

        }


        return Result.OK(pageList);
    }


    /**
     * 指数列表
     * @param req
     * @return
     */
    @RequestMapping({"stockIndexList.do"})
    @ResponseBody
    public Result<?> stockIndexList(HttpServletRequest req) {
        List<StStockTickerKLineList> totalIndexList = new ArrayList<>();

        // 上证指数
        StStockTickerKLineList sensex = stocksComponent.queryKLineDetailsByMarketAndCode(StocksComponent.HOSEIN, StocksComponent.HOSEIN_VN30_INDEX, "1min", "1");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");
//        List<StStockTickerKLineList> inIndexKLineList = stocksComponent.queryIndexKLineDetailsByMarketAndCode(StocksComponent.IN, StocksComponent.IN_CODE, "1min", "1");
//        if (CollectionUtils.isEmpty(inIndexKLineList)) {
//            inIndexKLineList = new ArrayList<>();
//        }
        // BJ指数
        StStockTickerKLineList dji = stocksComponent.queryKLineDetailsByMarketAndCode(StocksComponent.HOSEIN, StocksComponent.HOSEIN_HNXINDEX_INDEX, "1min", "1");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");
//        List<StStockTickerKLineList> usIndexKLineList = stocksComponent.queryIndexKLineDetailsByMarketAndCode(StocksComponent.USIN, StocksComponent.USIN_CODE, "1min", "1");
//        if (CollectionUtils.isEmpty(usIndexKLineList)) {
//            usIndexKLineList = new ArrayList<>();
//        }

        StStockTickerKLineList SZ_300 = stocksComponent.queryKLineDetailsByMarketAndCode(StocksComponent.HOSEIN, StocksComponent.HOSEIN_VNINDEX_INDEX, "1min", "1");
        // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_LIST, "stockIndexList");

        totalIndexList.add(SZ_300);

        // SH指数数据
        totalIndexList.add(sensex);
        // BJ指数
        totalIndexList.add(dji);

        List<StStockIndexVo> stStockIndexVos = new ArrayList<>();
        if (totalIndexList.size() > 0) {
            // 转换格式
            for (StStockTickerKLineList kLineList : totalIndexList) {
                String data = kLineList.getData();
                if (StringUtils.isBlank(data)) {
                    continue;
                }
                // 最终数据 包含K线 当前价格 涨跌幅
                StStockIndexVo stStockIndexVo = new StStockIndexVo();

                // K线数据
                StStockTickerKLineVO kLineVO = new StStockTickerKLineVO();
                String[] splitData = data.split(";");
                List<String> dataList = Arrays.asList(splitData);

                List<KLineDetail> dataDetails = new ArrayList<>();
                // 处理具体的字段  1时间戳,1昨日收,1今日开,1最高,1最低,1交易额,1交易量;
                for (String obj : dataList) {
                    String[] split = obj.split(",");
                    List<String> strings = Arrays.asList(split);
                    if (strings.size() < 7) {
                        continue;
                    }
                    KLineDetail kLineDetail = new KLineDetail();
                    kLineDetail.setTimestamp(String.valueOf(Long.parseLong(strings.get(0))*1000));
                    kLineDetail.setClose(strings.get(1));
                    kLineDetail.setOpen(strings.get(2));
                    kLineDetail.setHigh(strings.get(3));
                    kLineDetail.setLow(strings.get(4));
                    kLineDetail.setTurnover(strings.get(5));
                    kLineDetail.setVolume(strings.get(6));
                    dataDetails.add(kLineDetail);
                }

                BeanUtils.copyProperties(kLineList, kLineVO);
                kLineVO.setData(dataDetails);

                BeanUtils.copyProperties(kLineVO, stStockIndexVo);


                String code = kLineList.getCode();
                String market = kLineList.getMarket();
                StStockTickerDetails inStockTickerListInfo = stocksComponent.queryDetailsByMarketAndCode(market, code);

                // stocksComponent.thirdInterfaceStatistic(StocksComponent.MINI_PRICES, "stockIndexList");

                if (null != inStockTickerListInfo) {
                    StockTickerListInfo infoData = inStockTickerListInfo.getData();
                    if (null != infoData) {
                        stStockIndexVo.setPrice(infoData.getPrice());
                        stStockIndexVo.setUp(infoData.getUp());
                        stStockIndexVo.setChange(infoData.getChange());
                    }
                }

                stStockIndexVos.add(stStockIndexVo);
            }
        }
        return Result.OK(stStockIndexVos);
    }

    //查询 股票指数、大盘指数信息
    @RequestMapping({"getMarket.do"})
    @ResponseBody
    public ServerResponse getMarket() {
        return this.iStockService.getMarket();
    }

    //查询官网PC端交易 所有股票信息及指定股票信息
    @RequestMapping({"getStock.do"})
    @ResponseBody
    public ServerResponse getStock(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, @RequestParam(value = "stockPlate", required = false) String stockPlate, @RequestParam(value = "stockType", required = false) String stockType, @RequestParam(value = "keyWords", required = false) String keyWords, HttpServletRequest request) {
        if (TimerService.countrys.values().contains(stockType)) {
            Map<String, Object> params = new HashMap<>();
            params.put("stock_type", stockType);
            List<Map<String, Object>> list = sessionTemplate.selectList("com.nq.dao.StockMapper.newlist", params);
            int total = list.size();
            int start = pageSize * (pageNum - 1);
            List<Map<String, Object>> newlist = new LinkedList<>();

            for (int i = 0; i < total; i++) {
                if(i < start) {
                    continue;
                }
                Map<String, Object> map = list.get(i);
                Map<String, Object> item = new HashMap<>();
                item.put("code", map.get("Symbol"));
                item.put("name", map.get("Name"));
                item.put("hcrate", map.get("ChgPct"));
                newlist.add(item);
                if(newlist.size() >= pageSize) {
                    break;
                }
            }
            Map<String, Object> result = new HashMap<>();
            result.put("total", total);
            result.put("list", newlist);
            return ServerResponse.createBySuccess(result);
        }
        return this.iStockService.getStock(pageNum, pageSize, keyWords, stockPlate, stockType, request);
    }

    /**
     * 通过股票代码查询股票信息  新版数据
     * @param code
     * @param request
     * @return
     */
    @RequestMapping({"getStStock.do"})
    @ResponseBody
    public ServerResponse getStStock(@RequestParam("code") String code, HttpServletRequest request) {
        return this.iStockService.getStStock(code, request);
    }

    @RequestMapping({"getSingleStock.do"})
    @ResponseBody
    public ServerResponse getSingleStock(@RequestParam("code") String code, HttpServletRequest request) {
        return this.iStockService.getSingleStock(code, request);
    }

    //美股股票代码查询股票信息
    @RequestMapping({"getSingleStockByCode.do"})
    @ResponseBody
    public ServerResponse getSingleStockByCode(@RequestParam("code") String code) {
        return this.iStockService.getSingleStockByCode(code);
    }

    @RequestMapping({"getMinK.do"})
    @ResponseBody
    public ServerResponse getMinK(@RequestParam("code") String code, @RequestParam("time") Integer time, @RequestParam("ma") Integer ma, @RequestParam("size") Integer size) {
        return this.iStockService.getMinK(code, time, ma, size);
    }

    /*查询股票日线*/
    @RequestMapping({"getDayK.do"})
    @ResponseBody
    public ServerResponse getDayK(@RequestParam("code") String code) {
        return this.iStockService.getDayK_Echarts(code);
    }

    //查询股票历史数据数据
    @RequestMapping({"getMinK_Echarts.do"})
    @ResponseBody
    public ServerResponse getMinK_Echarts(@RequestParam("code") String code, @RequestParam("time") Integer time, @RequestParam("ma") Integer ma, @RequestParam("size") Integer size) {
        return this.iStockService.getMinK_Echarts(code, time, ma, size);
    }

    /*期货分时-k线*/
    @RequestMapping({"getFuturesMinK_Echarts.do"})
    @ResponseBody
    public ServerResponse getFuturesMinK_Echarts(@RequestParam("code") String code, @RequestParam("time") Integer time, @RequestParam("size") Integer size) {
        return this.iStockService.getFuturesMinK_Echarts(code, time, size);
    }

    /*指数分时-k线*/
    @RequestMapping({"getIndexMinK_Echarts.do"})
    @ResponseBody
    public ServerResponse getIndexMinK_Echarts(@RequestParam("code") String code, @RequestParam("time") Integer time, @RequestParam("size") Integer size) {
        return this.iStockService.getIndexMinK_Echarts(code, time, size);
    }

    /*查询期货日线*/
    @RequestMapping({"getFuturesDayK.do"})
    @ResponseBody
    public ServerResponse getFuturesDayK(@RequestParam("code") String code) {
        return this.iStockService.getFuturesDayK(code);
    }

    /*指数日线*/
    @RequestMapping({"getIndexDayK.do"})
    @ResponseBody
    public ServerResponse getIndexDayK(@RequestParam("code") String code) {
        return this.iStockService.getIndexDayK(code);
    }
//    //查询股票需要换数据源的股票
//    @RequestMapping({"stockDataBase.do"})
//    @ResponseBody
//    public ServerResponse stockDataBase() {
//        return this.iStockService.stockDataBase();
//    }

    @RequestMapping({"/tg/list.do"})
    @ResponseBody
    public Object tgList() {
        return TGStockApiUtil.list();
    }

    @RequestMapping({"/tg/real.do"})
    @ResponseBody
    public Object tgReal(String symbol) {
        return TGStockApiUtil.real(symbol);
    }

    @RequestMapping({"/tg/trend.do"})
    @ResponseBody
    public Object tgTrend(String symbol) {
        return TGStockApiUtil.trend(symbol);
    }

    @RequestMapping({"/tg/kline.do"})
    @ResponseBody
    public Object tgKline(String symbol, String type, String from, String to) {
        return TGStockApiUtil.kline(symbol, type, from, to);
    }

//    @RequestMapping({"/newlist.do"})
//    @ResponseBody
//    public Object newlist(int countryid, @RequestParam(defaultValue = "0") Integer page) {
//        JSONArray stocks = InvestingUtil.getStocks(countryid, page);
//        for (JSONObject stock : stocks.jsonIter()) {
//            int id = stock.getInt("Id");
//            String symbol = stock.getStr("Symbol");
//            String flag = stock.getStr("Flag");
//            stock.set("Symbol", flag.toLowerCase() + "_" + symbol);
//        }
//        timerService.updatePriceFromInv(stocks);
//        return ServerResponse.createBySuccess(stocks);
//    }

    @RequestMapping({"/newlist.do"})
    @ResponseBody
    public Object newlist(int countryid, @RequestParam(defaultValue = "0") Integer page, String stock_code) {
        String stock_type = TimerService.countrys.get(countryid);
        Map<String, Object> params = new HashMap<>();
        params.put("stock_code", stock_code);
        params.put("stock_type", stock_type);
        List<Map<String, Object>> list = sessionTemplate.selectList("com.nq.dao.StockMapper.newlist", params);
        List<?> newlist = list.stream().skip(100L * page).limit(100).collect(Collectors.toList());
        return ServerResponse.createBySuccess(newlist);
    }


    @RequestMapping({"/newkilne.do"})
    @ResponseBody
    public ServerResponse<?> newkilne(int stockid, String type) {
        int investing_id = MyDao.getInvestingIdByStockId(stockid);
        JSONArray stocks = InvestingUtil.kline(investing_id, type);
        return ServerResponse.createBySuccess(stocks);
    }


    /**
     * 涨停板
     */

    @PostMapping({"getztb.do"})
    @ResponseBody
    public ServerResponse getztb() {
        return this.iStockService.ztb();
    }

    /**
     * 大宗交易 列表
     */
    @RequestMapping({"getDzList.do"})
    @ResponseBody
    public ServerResponse getDzList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
                                    @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
        return this.stockDzService.getDzList(pageNum, pageSize);
    }

    /**
     * 大宗交易详情
     */
    @RequestMapping({"getDzDetails.do"})
    @ResponseBody
    public ServerResponse getDzDetails(@RequestParam(value = "dzId") int dzId) {
        return this.stockDzService.getDzDetails(dzId);
    }


    /**
     * vip 抢筹列表
     */
    @PostMapping({"getVipList.do"})
    @ResponseBody
    public ServerResponse getVipList() {
        return this.iStockService.ztb();
    }

    /**
     * vip 抢筹根据股票代码查询
     *
     * @param code
     * @return
     */

    @PostMapping({"getVipByCode.do"})
    @ResponseBody
    public ServerResponse getVipByCode(String code) {
        return this.iStockService.getVipByCode(code);
    }


    @RequestMapping({"/sg/list.do"})
    @ResponseBody
    public ServerResponse<?> list_sg(@RequestParam(defaultValue = "0") Integer page) {
        JSONArray stocks = InvestingUtil.getStocks(36, page);
        for(JSONObject stock :stocks.jsonIter()) {
            String symbol = stock.getStr("Symbol");
            stock.set("Symbol", "sg_" + symbol);
        }
        timerService.updatePriceFromInv(stocks);
        return ServerResponse.createBySuccess(stocks);
    }


    @RequestMapping({"/sg/kline.do"})
    @ResponseBody
    public ServerResponse<?> kline_sg(int stockid, String type) {
        JSONArray stocks = InvestingUtil.kline(stockid, type);
        return ServerResponse.createBySuccess(stocks);
    }


    @RequestMapping({"/initMarket"})
    @ResponseBody
    public Object initMarket(int id) {
        int r = timerService.initMarket(id);
        return ServerResponse.createBySuccess(r);
    }

    /**
     * 全量更新所有股票的实时行情
     * @return
     */
    @RequestMapping({"getAllMarketPrices.do"})
    @ResponseBody
    public ServerResponse getAllMarketPrices() {
        try {
            this.stocksComponent.getAllMarketPrices();
        } catch (Exception e) {
            e.printStackTrace();
            return ServerResponse.createByErrorMsg("全量更新所有股票的实时行情异常：" + e.getMessage());
        }
        return ServerResponse.createBySuccess();
    }


}